package model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
/**
 * Класс описывающий некоторую базу данных рейсов
 * @version 1.0
 * @see InterfaceFlights
 */
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Flights implements InterfaceFlights, Serializable,DataLoadable {

    /**
     * Список рейсов
     */
    private ArrayList<Flight> allFlights;

    /**
     * Конструктор без параметров
     */
    public Flights() {
        allFlights = new ArrayList<Flight>();
    }

    @Override
    public void addFlight(Flight newFlight) {
        this.allFlights.add(newFlight);
    }

    public boolean checkFlightsNumber(int flightsNumber) {
        int i = 0;
        while ((i < this.getSize()) && (this.allFlights.get(i).getFlightNumber() != flightsNumber)) {
            i++;
        }
        if (i < this.allFlights.size()) {
            return false;
        } else {
            return true;
        }
    }

    @Override
    public void addFlights(String fileName) {
        Flights temp = new Flights();
        Flight tempFlight = new Flight();
        temp = ProcessingFlights.loadData(fileName);
        for (int i = 0; i < temp.getSize(); i++) {
            tempFlight = temp.getFlightByIndex(i);
            if (checkFlight(tempFlight)) {
                this.addFlight(tempFlight);
            }
        }
    }

    @Override
    public Flights search(int flightsNumber, String aircraft,
            String arriveTown, String arriveAirport,
            String departTown, String departArport, Date departTime) {
        Flights temp = new Flights();
        Flight tempFlight = new Flight();
        boolean first = true;
        if (flightsNumber != -1) {
            if (first) {
                first = false;
                temp = this.searchByFlightsNumber(flightsNumber);
            }
        }
        if ((aircraft != null) && (temp!=null)){
            if (first) {
                first = false;
                temp = this.searchByAircraft(aircraft);
            } else {
                temp = temp.searchByAircraft(aircraft);
            }
        }
        if ((arriveTown != null) && (temp!=null)) {
            if (first) {
                first = false;
                temp = this.searchByArriveTown(arriveTown);
            } else {
                temp = temp.searchByArriveTown(arriveTown);
            }
        }
        if ((arriveAirport != null) && (temp!=null)) {
            if (first) {
                first = false;
                temp = this.searchByArriveAirport(arriveAirport);
            } else {
                temp = temp.searchByArriveAirport(arriveAirport);
            }
        }
        if ((departTown != null) && (temp!=null)) {
            if (first) {
                first = false;
                temp = this.searchByDepartTown(departTown);
            } else {
                temp = temp.searchByDepartTown(departTown);
            }
        }
        if ((departArport != null) && (temp!=null)) {
            if (first) {
                first = false;
                temp = this.searchByDepartAirport(departArport);
            } else {
                temp = temp.searchByDepartAirport(departArport);
            }
        }
        if (departTime != null&& (temp!=null)) {
            if (first) {
                first = false;
                temp = this.searchByDepartTime(departTime);
            } else {
                temp = temp.searchByDepartTime(departTime);
            }
        }
        return temp;
    }

    @Override
    public Flights searchByFlightsNumber(int flightsNumber) {
        int i = 0;
        Flights tempFlights = new Flights();
        while ((i<this.allFlights.size()) && (this.allFlights.get(i).getFlightNumber() != flightsNumber)) {
            i++;
        }
        if (i < this.allFlights.size()) {
            tempFlights.allFlights.add(this.getFlightByIndex(i));
            return tempFlights;
        } else {
            return null;
        }
    }

    @Override
    public Flights searchByAircraft(String str) {
        Flights a = new Flights();
        for (int i = 0; i < this.getSize(); i++) {
            if (str.equalsIgnoreCase(this.allFlights.get(i).getAircraft())) {
                a.allFlights.add(this.getFlightByIndex(i));
            }
        }
        if (a != null) {
            return a;
        } else {
            return null;
        }
    }

    @Override
    public Flights searchByArriveTown(String str) {
        Flights a = new Flights();
        for (int i = 0; i < this.getSize(); i++) {
            if (str.equalsIgnoreCase(this.allFlights.get(i).getRoute().getPointArrive().getTown())) {
                a.allFlights.add(this.getFlightByIndex(i));
            }
        }
        if (a != null) {
            return a;
        } else {
            return null;
        }
    }

    @Override
    public Flights searchByDepartTown(String str) {
        Flights a = new Flights();
        for (int i = 0; i < this.getSize(); i++) {
            if (str.equalsIgnoreCase(this.allFlights.get(i).getRoute().getPointDepart().getTown())) {
                a.allFlights.add(this.getFlightByIndex(i));
            }
        }
        if (a != null) {
            return a;
        } else {
            return null;
        }
    }

    @Override
    public Flights searchByArriveAirport(String str) {
        Flights a = new Flights();
        for (int i = 0; i < this.getSize(); i++) {
            if (str.equalsIgnoreCase(this.allFlights.get(i).getRoute().getPointArrive().getAirport())) {
                a.allFlights.add(this.getFlightByIndex(i));
            }
        }
        if (a != null) {
            return a;
        } else {
            return null;
        }
    }

    @Override
    public Flights searchByDepartAirport(String str) {
        Flights a = new Flights();
        for (int i = 0; i < this.getSize(); i++) {
            if (str.equalsIgnoreCase(this.allFlights.get(i).getRoute().getPointDepart().getAirport())) {
                a.allFlights.add(this.getFlightByIndex(i));
            }
        }
        if (a != null) {
            return a;
        } else {
            return null;
        }
    }

    @Override
    public Flights searchByDepartTime(Date sdate) {
        Flights a = new Flights();
        for (int i = 0; i < this.getSize(); i++) {
            if ((this.allFlights.get(i).getDepartTime().getHours() == sdate.getHours()) &&
                    (this.allFlights.get(i).getDepartTime().getMinutes() == sdate.getMinutes()))
            {
                a.allFlights.add(this.getFlightByIndex(i));
            }
        }
        if (a != null) {
            return a;
        } else {
            return null;
        }

    }

    @Override
    public Flight getFlightByIndex(int i) {
        return this.allFlights.get(i);
    }

    @Override
    public void deleteFlightByFlightsNumber(int flightsNumber) {
        int i = 0;
        while (this.allFlights.get(i).getFlightNumber() != flightsNumber) {
            i++;
        }
        if (i < this.allFlights.size()) {
            this.allFlights.remove(i);
        }
    }

    private boolean checkFlight(Flight checkedFlight) {
        int i = 0;
        Flight fTemp = new Flight();
        boolean flag = true;
        while (i < this.allFlights.size()) {
            fTemp = this.getFlightByIndex(i);
            if (checkedFlight.getFlightNumber() == fTemp.getFlightNumber()) {
                if (checkedFlight.getAircraft().equalsIgnoreCase(fTemp.getAircraft())) {
                    if (checkedFlight.getDepartTime() == fTemp.getDepartTime()) {
                        if (checkedFlight.getTravelTime() == fTemp.getTravelTime()) {
                            if (compareRoutes(checkedFlight.getRoute(), fTemp.getRoute())) {
                                flag = false;
                            } else {
                                if (flag) {
                                    flag = true;
                                }
                            }
                        } else {
                            if (flag) {
                                flag = true;
                            }
                        }
                    } else {
                        if (flag) {
                            flag = true;
                        }
                    }
                } else {
                    if (flag) {
                        flag = true;
                    }
                }
            } else {
                if (flag) {
                    flag = true;
                }
            }
            i++;
        }
        return flag;
    }

    private boolean compareRoutes(Route route, Route route0) {
        if (route.getPointArrive().getTown().equalsIgnoreCase(route0.getPointArrive().getTown())) {
            if (route.getPointArrive().getAirport().equalsIgnoreCase(route0.getPointArrive().getAirport())) {
                if (route.getPointDepart().getTown().equalsIgnoreCase(route0.getPointDepart().getTown())) {
                    if (route.getPointDepart().getAirport().equalsIgnoreCase(route0.getPointDepart().getAirport())) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    @Override
    /**
     * Метод, который возвращаяет количество объектов в коллекции 
     * @return int количество объектов
     */
    public int getSize() {
        return this.allFlights.size();
    }

    @Override
    public void updateFlight(Flight newFlight) {
        int i = 0;
        while (this.allFlights.get(i).getFlightNumber() != newFlight.getFlightNumber()) {
            i++;
        }
        if (i < this.allFlights.size()) {
            this.getFlightByIndex(i).setAircraft(newFlight.getAircraft());
            this.getFlightByIndex(i).setRoute(newFlight.getRoute());
            this.getFlightByIndex(i).setDepartTime(newFlight.getDepartTime());
            this.getFlightByIndex(i).setTravelTime(newFlight.getTravelTime());
        }
    }
    
    /**
     * Метод, который проверяет, содержится ли переданный объект в коллексии
     * @param element Объект
     * @return boolean результат проверки
     */ 
    public boolean contains(Model element){
        Flight flight = (Flight)element;
        if(this.search(flight.getFlightNumber(), flight.getAircraft(), 
                        flight.getRoute().getPointArrive().getTown(), 
                        flight.getRoute().getPointArrive().getAirport(), 
                        flight.getRoute().getPointDepart().getTown(), 
                        flight.getRoute().getPointDepart().getAirport(),
                        flight.getDepartTime()) != null)
            return true;
        else
            return false;
    
    }

    /**
     * Метод, который заменяет объект в колекции новым объектом(на основе ключевого поля) 
     * @param element Объект
     */ 
    public void update( Model newelement) {
        this.updateFlight((Flight)newelement);
    }

    /**
     * Метод, который добавляет объект в колекцию
     * @param element Объект
     */ 
    public void add(Model flight) {
        this.addFlight((Flight)flight);
    }
    
    /**
     * Метод, который возвращает объект по индексу 
     * @param i Индекс
     * @return Model Объект
     */   
    public Model getElementByID(int i) {
       return this.getFlightByIndex(i);
    }
}
